package com.passion.context;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
import com.passion.cache.enums.CacheType;
import com.passion.common.util.FileUtil;
import com.passion.fs.enums.StorageType;
import com.passion.mq.enums.MqType;
import com.passion.search.enums.SearchType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 类描述：上下文路径工具类
 *
 * @author ZhuYin
 * @since 2024年10月14日
 */
@Slf4j
@Component
public class SysContext {

    public static ConfigurableEnvironment configurableEnvironment;

    @Resource
    public void setEnv(ConfigurableEnvironment configurableEnvironment) {
        SysContext.configurableEnvironment = configurableEnvironment;
    }

    /**
     * 方法说明：获取系统访问的上下文路径
     * 当配置了context-path属性之后，系统中部分的URL会以该路径作为前缀，例如：/api/xxx
     * @return {@link String }
     */
    public static String getContextPath() {
        String contextPath = configurableEnvironment.getProperty("server.servlet.context-path");
        if (StringUtils.isEmpty(contextPath)) {
            contextPath = "";
        } else {
            if ("/".equals(contextPath)) {
                contextPath = "";
            }
            contextPath = FileUtil.sopPath(contextPath);
            if (contextPath.endsWith("/")) {
                contextPath = contextPath.substring(0, contextPath.length() - 1);
            }
        }
        return contextPath;
    }

    /**
     * 方法说明：打印系统信息
     */
    public static void logSysInfo() throws UnknownHostException {
        // 获取服务器IP
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = configurableEnvironment.getProperty("server.port");
        String contextPath = getContextPath();
        String protocol = "http";
        boolean sslEnabled = Boolean.parseBoolean(configurableEnvironment.getProperty("server.ssl.enabled", "false"));
        if (sslEnabled) {
            protocol = "https";
        }

        StringBuilder sb = new StringBuilder();
        sb.append("\n#####################################################################################");
        String jdbcInfo = buildJdbcInfo();
        sb.append(jdbcInfo);
        String cacheInfo = buildCacheInfo();
        sb.append(cacheInfo);
        String searchInfo = buildSearchInfo();
        sb.append(searchInfo);
        String mqInfo = buildMqInfo();
        sb.append(mqInfo);
        String fileSystemInfo = buildFileSystemInfo();
        sb.append(fileSystemInfo);
        sb.append("\n#####################################################################################\n");

        sb.append("\n#####################################################################################");
        sb.append("\n#\tApplication is running! Access URLs:");
        sb.append("\n#\tLocal访问网址: \t\t").append(protocol).append("://localhost:").append(port).append(contextPath);
        sb.append("\n#\tExternal访问网址: \t").append(protocol).append("://").append(ip).append(":").append(port).append(contextPath);
        String monitorInfo = buildMonitorInfo(protocol, ip, port, contextPath);
        sb.append(monitorInfo);
        String knife4jInfo = buildKnife4jInfo(protocol, ip, port, contextPath);
        sb.append(knife4jInfo);
        sb.append("\n#####################################################################################\n");

        log.info(sb.toString());
    }



    /**
     * 方法说明：获取数据库信息串
     *
     * @return 返回数据库信息
     * @author ZhuYin
     * @since 2024年12月15日
     */
    private static String buildJdbcInfo() {
        StringBuilder sb = new StringBuilder();
        String jdbcUrl = configurableEnvironment.getProperty("spring.datasource.url", "");
        DbType dbType = JdbcUtils.getDbType(jdbcUrl);
        // 数据库信息
        sb.append("\n#\t当前JDBC数据库信息: 类型=").append(dbType).append(" url=").append(jdbcUrl);
        return sb.toString();
    }

    /**
     * 方法说明：获取缓存信息串
     *
     * @return 返回缓存信息串
     * @author ZhuYin
     * @since 2024年12月15日
     */
    private static String buildCacheInfo() {
        StringBuilder sb = new StringBuilder();
        // 缓存类型
        String cacheType = configurableEnvironment.getProperty("archives.cache.type");
        if (CacheType.REDIS.getType().equals(cacheType)) {
            // 使用redis作为缓存
            String redisClusterNodes = configurableEnvironment.getProperty("spring.redis.cluster.nodes");
            String redisSentinelNodes = configurableEnvironment.getProperty("spring.redis.sentinel.nodes");
            String redisInfo = configurableEnvironment.getProperty("spring.redis.host", "localhost") + ":" + configurableEnvironment.getProperty("spring.redis.port", "6379") + "  DB:" + configurableEnvironment.getProperty("spring.redis.database");
            // Redis 部署模式
            boolean clusterMode = StringUtils.hasLength(redisClusterNodes);
            boolean sentinelMode = StringUtils.hasLength(redisSentinelNodes);
            String redisMode = "standalone";
            if (clusterMode) {
                redisMode = "cluster";
                redisInfo = redisClusterNodes;
            } else if (sentinelMode) {
                redisMode = "sentinel";
                redisInfo = redisSentinelNodes;
            }
            sb.append("\n#\t当前使用的缓存类型：redis 当前Redis信息:").append(redisInfo).append(" 部署模式:").append(redisMode);
        } else if (CacheType.LOCAL.getType().equals(cacheType)) {
            // 使用本地缓存
            sb.append("\n#\t当前使用的缓存类型：local");
        }
        return sb.toString();
    }

    /**
     * 方法说明：获取搜索引擎信息串
     *
     * @return 返回缓存信息串
     * @author ZhuYin
     * @since 2024年12月15日
     */
    private static String buildSearchInfo() {
        StringBuilder sb = new StringBuilder();
        String searchType = configurableEnvironment.getProperty("archives.search.type");
        if (SearchType.SOLR.getType().equals(searchType)) {
            // 使用solr搜索引擎
            String solrInfo = configurableEnvironment.getProperty("spring.data.solr.host", "http://localhost:8983/solr") + "/#/" + configurableEnvironment.getProperty("spring.data.solr.defaultCore", "archives") + "/core-overview";
            // Solr 部署模式
            String solrMode = Boolean.parseBoolean(configurableEnvironment.getProperty("spring.data.solr.cluster", "false")) ? "cluster" : "standalone";
            sb.append("\n#\t当前使用的搜索引擎类型：solr 当前Solr信息:").append(solrInfo).append(" 部署模式:").append(solrMode);
        } else if (SearchType.EASY_ES.getType().equals(searchType)) {
            // 使用easy-es搜索引擎 TODO
            sb.append("\n#\t当前使用的搜索引擎类型：easy-es 当前easy-es信息:").append("xxx").append(" 部署模式:").append("xxx");
        } else if (SearchType.ELASTIC_SEARCH.getType().equals(searchType)) {
            // 使用elastic-search搜索引擎 TODO
            sb.append("\n#\t当前使用的搜索引擎类型：elastic-search 当前elastic-search信息:").append("xxx").append(" 部署模式:").append("xxx");
        }
        return sb.toString();
    }

    /**
     * 方法说明：获取mq信息串
     *
     * @return 返回mq信息串
     * @author ZhuYin
     * @since 2024年12月15日
     */
    private static String buildMqInfo() {
        StringBuilder sb = new StringBuilder();
        String mqType = configurableEnvironment.getProperty("archives.mq.type");
        if (MqType.RABBITMQ.getType().equals(mqType)) {
            String rabbitmqInfo = "http://" + configurableEnvironment.getProperty("spring.rabbitmq.host", "localhost") + ":15672";
            // rabbitmq 部署模式
            String rabbitmqMode = StringUtils.hasLength(configurableEnvironment.getProperty("spring.rabbitmq.addresses")) ? "cluster" : "standalone";
            rabbitmqInfo = StringUtils.hasLength(configurableEnvironment.getProperty("spring.rabbitmq.addresses")) ? configurableEnvironment.getProperty("spring.rabbitmq.addresses") : rabbitmqInfo;
            sb.append("\n#\t当前使用的mq类型：rabbitmq 当前RabbitMQ信息:").append(rabbitmqInfo).append(" 部署模式:").append(rabbitmqMode);
        } else if (MqType.ROCKETMQ.getType().equals(mqType)) {
            String rocketMqInfo = "http://" + configurableEnvironment.getProperty("rocketmq.name-server", "localhost:9876");
            String rocketMqMode = "standalone";
            sb.append("\n#\t当前使用的mq类型：rocketmq 当前RocketMQ信息:").append(rocketMqInfo).append(" 部署模式:").append(rocketMqMode);
        }

        return sb.toString();
    }

    /**
     * 方法说明：获取文件系统信息
     *
     * @return 返回文件系统信息串
     * @author ZhuYin
     * @since 2025年01月06日
     */
    private static String buildFileSystemInfo() {
        StringBuilder sb = new StringBuilder();
        String fileSystemType = configurableEnvironment.getProperty("archives.fs.type");
        if (StorageType.LOCAL.getType().equals(fileSystemType)) {
            // 本地文件系统
            String localFileSystemInfo = configurableEnvironment.getProperty("archives.fs.local.directory", "D:/szda/data/fileServer/upload");
            String endpoint = configurableEnvironment.getProperty("archives.fs.local.endpoint", "http://localhost:8081");
            String nginxUrl = configurableEnvironment.getProperty("archives.fs.local.nginxUrl", "/files");
            sb.append("\n#\t当前使用的文件系统类型：local 文件存储根路径:").append(localFileSystemInfo).append(" endpoint:").append(endpoint).append(" nginxUrl:").append(nginxUrl);
        } else if (StorageType.MINIO.getType().equals(fileSystemType)) {
            // minio文件系统

        }
        return sb.toString();
    }

    /**
     * 方法说明：获取监控访问信息串
     *
     * @param protocol      协议
     * @param ip            ip
     * @param port          端口
     * @param contextPath   上下文路径
     * @return              返回监控访问信息串
     * @author ZhuYin
     * @since 2024年12月15日
     */
    private static String buildMonitorInfo(String protocol, String ip, String port, String contextPath) {
        StringBuilder sb = new StringBuilder();
        // 监控是否开启（默认：开启）
        boolean javamelodyEnabled = Boolean.parseBoolean(configurableEnvironment.getProperty("javamelody.enabled", "true"));
        sb.append((javamelodyEnabled ? "\n#\t\t监控访问网址: \t\t" + protocol + "://" + ip + ":" + port + contextPath + configurableEnvironment.getProperty("javamelody.init-parameters.monitoring-path") : ""));
        return sb.toString();
    }

    /**
     * 方法说明：获取接口文档访问信息串
     *
     * @param protocol      协议
     * @param ip            ip
     * @param port          端口
     * @param contextPath   上下文路径
     * @return              返回接口文档访问信息串
     * @author ZhuYin
     * @since 2024年12月15日
     */
    private static String buildKnife4jInfo(String protocol, String ip, String port, String contextPath) {
        StringBuilder sb = new StringBuilder();
        // knife4j是否开启（默认：开启）
        boolean knife4jEnabled = Boolean.parseBoolean(configurableEnvironment.getProperty("knife4j.enabled", "true"));
        sb.append((knife4jEnabled ? "\n#\t接口文档访问网址: \t\t" + protocol + "://" + ip + ":" + port + contextPath + "/doc.html" : ""));
        return sb.toString();
    }

}
